<?php

namespace SinoPHP\BbdBoss\Library;

use SinoPHP\BbdBoss\Model\AdminAuth as AdminAuthModel;
use Upfor\UpforPHP\Http\Url;

/**
 * 管理员权限&菜单
 *
 * 超级管理员:
 *      管理员用户只要属于`超级管理员角色组`, 即是超级管理员, 便拥有所有可用(status=1)权限&菜单
 *
 * 角色/用户组:
 *      一个角色拥有多个权限节点;
 *      一个用户可同时拥有多个角色和独立的权限;
 *
 * 节点类型:
 *      menu:       一级菜单, 无任何链接或页面
 *      page:       页面(子菜单), 一般是GET请求的展示页面
 *      action:     操作, 一般不显示, 可以是页面, 也可以是API
 *      button:     (暂不可用) 页面上的按钮, 用于控制按钮是否可见
 *
 * URL权限控制:
 *      对于page/action, 通过 controller + action + params 可确定唯一性, 并能判断当前URL是否与某权限匹配
 *      controller: 控制器
 *      action:     控制器下所属方法
 *      params:     $_GET 或 Url::parseUrl() 的参数信息进行匹配, params字段是个JSON格式的关联数组存于数据库中
 *
 * 排序:
 *      sort:       值越小, 排序越靠前; 仅作用于同一菜单范围内
 *
 * 是否显示:
 *      display:    是否显示
 *
 * 启用状态:
 *      status:     当禁用时, 包括超级管理员也无查看OR操作权限
 *
 * CSS样式:
 *      style:      CSS样式, class类名, 输出到class="{style}"
 */
class AdminAuth {

    /**
     * 超级管理员角色组
     */
    const SUPER_ROLE_ID = 1;

    /**
     * 管理员权限Model
     *
     * @var AdminAuthModel
     */
    protected $model;

    public function __construct() {
        $this->model = model('AdminAuth');
    }

    /**
     * 判断是否为超级管理员
     *
     * @param  integer $userId
     * @return boolean
     */
    public function isSuper($userId = null) {
        // 根据登录信息判断
        if (!$userId && isAdminLogin()) {
            $userInfo = getCurrentAdminUserInfo();
            $roles = $userInfo['roles'];

            return in_array($this->getSuperRoleId(), (array) $roles);
        }

        if (!$userId) {
            return false;
        }

        // 获取拥有角色
        $userRoles = $this->model->getUserRoleIds($userId);

        // 判断是否在`超级管理员角色组`里
        return in_array($this->getSuperRoleId(), (array) $userRoles);
    }

    /**
     * 获取超级管理员所属角色ID
     *
     * @return integer
     */
    public function getSuperRoleId() {
        return self::SUPER_ROLE_ID;
    }

    /**
     * 获取用户权限信息
     *
     * @param integer $userId
     * @return array
     */
    public function getPermissionByUser($userId) {
        // 超级管理员拥有所有权限
        if ($this->isSuper($userId)) {
            $userNodes = null;
        } else {
            $userNodes = $this->getNodesByUser($userId);
        }

        // 权限列表
        return $this->model->getPermissionsByByNodeIds($userNodes);
    }

    /**
     * 获取所有权限列表
     *
     * @return array
     */
    public function getAllPermissions() {
        $key = 'AdminAllPermissions';
        $permissions = cache($key);
        if (!$permissions) {
            $permissions = $this->model->getPermissionsByByNodeIds(null);

            cache($key, $permissions, 300);
        }

        return $permissions;
    }

    /**
     * 获取用户角色列表
     *
     * @param  integer $userId
     * @return array
     */
    public function getRolesByUser($userId) {
        return $this->model->getUserRoleIds($userId);
    }

    /**
     * 获取用户节点列表
     *
     * @param  integer $userId
     * @return array
     */
    public function getNodesByUser($userId) {
        return $this->model->getUserNodes($userId);
    }

    /**
     * 获取用户拥有的菜单列表
     *
     * @param  $userId
     * @return array
     */
    public function getMenusByUser($userId) {
        // 超级管理员拥有所有菜单
        if ($this->isSuper($userId)) {
            $userNodes = null;
        } else {
            $userNodes = $this->getNodesByUser($userId);
        }

        // 获取拥有的菜单, 并进行格式化
        $allMenus = $this->model->getDisplayMenusByNodeIds($userNodes);
        foreach ($allMenus as $key => $row) {
            $url = '';
            if (!empty($row['controller']) && !empty($row['action'])) {
                $row['params'] = $this->decodeParams($row['params']);

                $url = Url::buildUrl($row['controller'] . '/' . $row['action'], $row['params']);
            }

            $allMenus[$key] = array(
                'node_id' => $row['node_id'],
                'pid' => $row['pid'],
                'title' => $row['title'],
                'url' => $url,
                'style' => $row['style'],
            );
        }
        $classifyMenus = $this->classify($allMenus, 0, 1);

        return $classifyMenus;
    }

    /**
     * 菜单归类
     *
     * @param  array   $data
     * @param  integer $pid
     * @param  integer $level
     * @return array
     */
    protected function classify($data, $pid = 0, $level = 1) {
        $list = array();
        foreach ($data as $key => $val) {
            if ($val['pid'] == $pid) {
                $val['level'] = $level;
                unset($data[$key]);

                $val['sub'] = $this->classify($data, $val['node_id'], $level + 1);

                $list[] = $val;
            }
        }

        return $list;
    }

    /**
     * 编码参数
     *
     * @param  mixed $data
     * @return string
     */
    public function encodeParams($data) {
        if (!is_array($data) && !is_object($data)) {
            $data = array();
        }

        return json_encode($data, JSON_UNESCAPED_UNICODE);
    }

    /**
     * 解码参数
     *
     * @param  string $data
     * @return array
     */
    public function decodeParams($data) {
        if (is_array($data)) {
            return $data;
        } elseif (is_object($data)) {
            return (array) $data;
        } elseif (is_string($data)) {
            $data = json_decode($data, true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                $data = array();
            }

            return (array) $data;
        } else {
            return array();
        }
    }

    public function getMatchedNodes(array $condition) {
        return $this->model->getMatchedNodes($condition);
    }

}
